// VS_BEGIN
#version 330 core
layout (location = 0) in vec3 aPos;
layout (location = 1) in vec2 aCoord;
layout (location = 2) in vec3 aNormal;

uniform mat4 u_model;

layout (std140) uniform EngineUBO
{
    mat4 u_view;
    mat4 u_project;
    vec3 u_camPos;
};

out vec3 g_worldPos;
out vec3 g_normal;
out vec2 g_coord;

void main() {
    g_worldPos = vec3(u_model * vec4(aPos, 1.0f));
    g_normal = vec3(u_model * vec4(aNormal, 0.0f));
    g_coord = aCoord;
    gl_Position = u_project * u_view * vec4(g_worldPos, 1.0f);
}
// VS_END

// FS_BEGIN
#version 330 core

in vec3 g_worldPos;
in vec3 g_normal;
in vec2 g_coord;

out vec4 FragColor;

layout (std140) uniform EngineUBO
{
    mat4 u_view;
    mat4 u_project;
    vec3 u_camPos;
};

layout (std140) uniform LightUBO
{
    mat4 u_lights[64];
    int u_lightNum;
};

uniform float       u_shineness;
uniform vec3        u_ambientColor;
uniform sampler2D   u_diffuseMap;
uniform sampler2D   u_specularMap;

vec3 CalPointLight(mat4 light, vec3 diffColor, vec3 specColor) {
    vec3 lPos = light[0].xyz;
    vec3 lColor = light[1].xyz;
    float lStrength = light[1].w;
    vec3 dir = normalize(lPos - g_worldPos);
    float dis = distance(lPos, g_worldPos);
    vec3 camDir = normalize(u_camPos - g_worldPos);

    vec3 ambientFactor = u_ambientColor * diffColor;
    vec3 diffFactor = diffColor * max(dot(dir, normalize(g_normal)), 0.0f) * lColor;
    vec3 specFactor = specColor * max(dot(reflect(-dir, normalize(g_normal)), camDir), 0.0f) * lColor;

    return (ambientFactor + diffFactor + specFactor) * (1.0f / dis) * lStrength; 
}

vec3 CalDirectLight(mat4 light, vec3 diffColor, vec3 specColor) {
    vec3 ldir = -light[2].xyz;
    vec3 lColor = light[1].xyz;
    float lStrength = light[1].w;
    vec3 camDir = normalize(u_camPos - g_worldPos);

    vec3 ambientFactor = u_ambientColor * diffColor;
    vec3 diffFactor = diffColor * max(dot(ldir, normalize(g_normal)), 0.0f) * lColor;
    vec3 specFactor = specColor * pow(max(dot(reflect(-ldir, normalize(g_normal)), camDir), 0.0f), u_shineness) * lColor;

    return (ambientFactor + diffFactor + specFactor) * lStrength;
}

void main() {
    vec4 diffColor = texture(u_diffuseMap, g_coord); 
    vec4 specColor = texture(u_specularMap, g_coord); 
    vec3 outColor = vec3(0.0f, 0.0f, 0.0f);
    for (int i = 0; i < u_lightNum; ++i) {
        float type = u_lights[i][0].w;
        if (type == 0.0f) {
            outColor += CalPointLight(u_lights[i], diffColor.xyz, specColor.xyz);
        } else if (type == 1.0f) {
            outColor += CalDirectLight(u_lights[i], diffColor.xyz, specColor.xyz);
        }
        
    }
    FragColor = vec4(outColor, 1.0f);
}
// FS_END